package com.zsk.shop.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsk.shop.common.base.BaseResponse;
import com.zsk.shop.common.base.NoMsgException;
import com.zsk.shop.common.utils.EntityConvertUtils;
import com.zsk.shop.common.utils.HttpContext;
import com.zsk.shop.common.utils.ToolUtil;
import com.zsk.shop.entity.GopMenu;
import com.zsk.shop.entity.GopRole;
import com.zsk.shop.entity.GopRoleMenuRelation;
import com.zsk.shop.mapper.GopMenuMapper;
import com.zsk.shop.model.params.GopMenuAddParam;
import com.zsk.shop.model.params.GopMenuEditParam;
import com.zsk.shop.model.results.GopMenuDto;
import com.zsk.shop.model.results.GopMenuLevelListResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author stylefeng
 * @since 2018-12-07
 */
@Service
@DS("master")
public class GopMenuService extends ServiceImpl<GopMenuMapper, GopMenu> {

    @Resource
    private GopMenuMapper baseMapper;

    @Resource
    private GopRelationService relationService;

    @Autowired
    private GopRoleService roleService;

    /**
     * 添加菜单
     *
     * @author fengshuonan
     * @Date 2018/12/23 5:59 PM
     */
    @Transactional
    public BaseResponse addMenu(GopMenuAddParam param) {
        if (ToolUtil.isOneEmpty(param, param.getMenuFlag(), param.getName(), param.getMenuNo())) {
            throw new NoMsgException(400, "请求数据不完整或格式错误！");
        }
        if (ToolUtil.isEmpty(param.getPMenuNo())) {
            param.setPMenuNo("");
        }
        if (ToolUtil.isEmpty(param.getDescription())) {
            param.setDescription("");
        }
        if (ToolUtil.isEmpty(param.getIcon())) {
            param.setIcon("");
        }
        if (ToolUtil.isEmpty(param.getSort())) {
            param.setSort(20);
        }
        GopMenuDto menuDto = EntityConvertUtils.convertAToB(param, GopMenuDto.class);
        GopMenu resultMenu = this.menuSetInfo(menuDto);
        //如果url存在，则不能够新增
        GopMenu haveMenu = this.queryByMenuNo(resultMenu.getMenuNo());
        if (ToolUtil.isNotEmpty(haveMenu)) {
            return BaseResponse.error("当前menuNo已存在，请取用别名后操作");
        }
        this.save(resultMenu);
        return BaseResponse.success();
    }

    private GopMenu queryByMenuNo(String menuNo) {
        LambdaQueryWrapper<GopMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GopMenu::getMenuNo, menuNo);
        queryWrapper.last("limit 1");
        return this.getOne(queryWrapper);
    }

    /**
     * 根据请求的父级菜单编号设置层级
     *
     * @author fengshuonan
     * @Date 2018/12/23 5:54 PM
     */
    public GopMenu menuSetInfo(GopMenuDto menuParam) {
        GopMenu resultMenu = new GopMenu();
        BeanUtil.copyProperties(menuParam, resultMenu);
        if (ToolUtil.isEmpty(menuParam.getPMenuNo()) || menuParam.getPMenuNo().equals(0L)) {
            resultMenu.setPMenuNo("");
            resultMenu.setLevels(1);
            resultMenu.setUrl("/" + menuParam.getMenuNo());
            //如果修改的是1级，把2级的都替换掉
            if (ToolUtil.isNotEmpty(menuParam.getId())) {
                GopMenu oldMenu = this.baseMapper.getById(menuParam.getId());
                this.updateMenuNoLevel2ByLevel1(oldMenu.getMenuNo(), menuParam.getMenuNo());
            }
        } else {
            String pMenuNo = menuParam.getPMenuNo();
            GopMenu pMenu = this.getByMenuNo(pMenuNo);
            Integer pLevels = pMenu.getLevels();
            resultMenu.setLevels(pLevels + 1);
            resultMenu.setUrl(pMenu.getUrl() + "/" + menuParam.getMenuNo());
        }
        resultMenu.setStatus(false);
        resultMenu.setCreateTime(new Date());
        resultMenu.setUpdateTime(new Date());
        resultMenu.setCreateUser(HttpContext.getUserId());
        resultMenu.setUpdateUser(HttpContext.getUserId());
        return resultMenu;
    }

    private void updateMenuNoLevel2ByLevel1(String oldMenuNo, String menuNo) {
        LambdaQueryWrapper<GopMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(GopMenu::getLevels, 1);
        queryWrapper.eq(GopMenu::getPMenuNo, oldMenuNo);
        List<GopMenu> gopMenuList = this.list(queryWrapper);
        if (ToolUtil.isEmpty(gopMenuList)) {
            return;
        }
        for (GopMenu gopMenu : gopMenuList) {
            String oldPMenuNo = gopMenu.getPMenuNo();
            gopMenu.setPMenuNo(menuNo);
            gopMenu.setUrl(gopMenu.getUrl().replaceFirst(oldPMenuNo, menuNo));
        }
        this.updateBatchById(gopMenuList);
    }

    public GopMenu getByMenuNo(String menuNo) {
        LambdaQueryWrapper<GopMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GopMenu::getMenuNo, menuNo);
        queryWrapper.last("limit 1");
        return this.getOne(queryWrapper);
    }

    /**
     * 更新菜单
     *
     * @author fengshuonan
     * @Date 2019/2/27 4:09 PM
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateMenu(GopMenuEditParam param) {
        //如果菜单为空
        if (ToolUtil.isOneEmpty(param, param.getId(), param.getMenuFlag(),
                param.getSort(), param.getName(), param.getMenuNo())) {
            throw new NoMsgException(400, "请求数据不完整或格式错误！");
        }
        if (ToolUtil.isEmpty(param.getPMenuNo())) {
            param.setPMenuNo("");
        }
        //获取旧的菜单
        GopMenu menu = this.getById(param.getId());
        if (menu == null) {
            throw new NoMsgException(400, "请求数据不完整或格式错误！");
        }
        String oldIcon = menu.getIcon();
        String oldDescription = menu.getDescription();
        //设置父级菜单编号
        BeanUtil.copyProperties(param, menu);
        GopMenuDto menuDto = EntityConvertUtils.convertAToB(param, GopMenuDto.class);
        GopMenu resultMenu = this.menuSetInfo(menuDto);
        if (ToolUtil.isEmpty(param.getIcon())) {
            resultMenu.setIcon(oldIcon);
        }
        if (ToolUtil.isEmpty(param.getDescription())) {
            resultMenu.setDescription(oldDescription);
        }
        this.updateById(resultMenu);
    }

    /**
     * 删除菜单
     *
     * @author stylefeng
     * @Date 2017/5/5 22:20
     */
    @Transactional
    public void delMenu(Long id) {
        //删除菜单
        baseMapper.deleteById(id);
        //删除关联的relation
        baseMapper.deleteRelationByMenu(id);
    }

    public List<String> getMenuUrlByRoleId(Long roleId) {
        //判断角色是否禁用
        GopRole gopRole = roleService.queryUnInValidByRoleId(roleId);
        if (ToolUtil.isEmpty(gopRole)) {
            return new ArrayList<>();
        }
        List<GopMenu> gopMenuList = getRelationsByRoleId(roleId);
        return gopMenuList.stream().map(GopMenu::getUrl).collect(Collectors.toList());
    }

    /**
     * 获取菜单列表树
     *
     * @return
     * @date 2017年2月19日 下午1:33:51
     */
    public BaseResponse<GopMenu> menuTreeList() {
        LambdaQueryWrapper<GopMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(GopMenu::getSort);
        List<GopMenu> gopMenuList = this.baseMapper.selectList(queryWrapper);
        List<GopMenu> gopMenuListA = gopMenuList.stream().filter(x -> x.getLevels().equals(1)).collect(Collectors.toList());
        List<GopMenu> gopMenuListB = gopMenuList.stream().filter(x -> x.getLevels().equals(2)).collect(Collectors.toList());
        List<GopMenuLevelListResult> levelListA = EntityConvertUtils.convertAListToBList(gopMenuListA, GopMenuLevelListResult.class);
        List<GopMenuLevelListResult> levelListB = EntityConvertUtils.convertAListToBList(gopMenuListB, GopMenuLevelListResult.class);
        for (GopMenuLevelListResult listResult : levelListA) {
            List<GopMenuLevelListResult> levelListC = levelListB.stream().filter(x -> x.getPMenuNo().equals(listResult.getMenuNo())).collect(Collectors.toList());
            listResult.setMenus(levelListC);
        }
        return BaseResponse.success(levelListA);
    }

    /**
     * 获取菜单列表树
     *
     * @return
     * @date 2017年2月19日 下午1:33:51
     */
    public BaseResponse menuTreeListByMenuUrls(List<String> menuUrls) {
        LambdaQueryWrapper<GopMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(GopMenu::getUrl, menuUrls);
        queryWrapper.orderByDesc(GopMenu::getSort);
        List<GopMenu> gopMenuList = this.baseMapper.selectList(queryWrapper);
        List<GopMenu> gopMenuListA = gopMenuList.stream().filter(x -> x.getLevels().equals(1)).collect(Collectors.toList());
        List<GopMenu> gopMenuListB = gopMenuList.stream().filter(x -> x.getLevels().equals(2)).collect(Collectors.toList());
        List<GopMenuLevelListResult> levelListA = EntityConvertUtils.convertAListToBList(gopMenuListA, GopMenuLevelListResult.class);
        List<GopMenuLevelListResult> levelListB = EntityConvertUtils.convertAListToBList(gopMenuListB, GopMenuLevelListResult.class);
        for (GopMenuLevelListResult listResult : levelListA) {
            List<GopMenuLevelListResult> levelListC = levelListB.stream().filter(x -> x.getPMenuNo().equals(listResult.getMenuNo())).collect(Collectors.toList());
            listResult.setMenus(levelListC);
        }
        return BaseResponse.success(levelListA);
    }

    public List<GopMenu> getRelationsByRoleId(Long roleId) {
        LambdaQueryWrapper<GopRoleMenuRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GopRoleMenuRelation::getRoleId, roleId);
        List<GopRoleMenuRelation> relations = relationService.getBaseMapper().selectList(queryWrapper);
        List<Long> menusId = relations.stream().map(GopRoleMenuRelation::getMenuId).collect(Collectors.toList());
        if (ToolUtil.isEmpty(menusId)) {
            return new ArrayList<>();
        }
        return baseMapper.selectList(new QueryWrapper<GopMenu>().in("id", menusId));
    }

    public List<String> getMenuNamesByRoleId(Long roleId) {
        List<GopMenu> gopMenuList = getRelationsByRoleId(roleId);
        return gopMenuList.stream().map(GopMenu::getName).collect(Collectors.toList());
    }
}
